#include "GribCompute.h"
#include "GribWrapper.h"
#include "OCMain/Timer.h"
#include <future>

namespace OCPP
{
	using namespace Volume;
	void GribCompute::extract(int levelIndex, int timeIndex, const VolumeOptions& options)
	{
		std::map<String, std::shared_ptr<GribWrapper> > ncNcWrapperList;
		std::vector<std::tuple<String, GribReadIndexList> > ncOutputListList;

		for (const auto& [fileName, varName] : _computeList)
		{
			if (ncNcWrapperList[fileName] == nullptr)
			{
				ncNcWrapperList[fileName] = std::make_shared<GribWrapper>();
				if (!ncNcWrapperList[fileName]->open(fileName))
				{
					OCPP_LOG_ERROR << fileName << " can't open.\n";
					return;
				}
			}
			auto data = ncNcWrapperList[fileName]->read(varName, levelIndex, timeIndex, options);
			ncOutputListList.push_back({ fileName, data });
		}

		if (ncOutputListList.size() == 0)
		{
			return;
		}

		const auto& [fileName, data] = ncOutputListList[0];

		auto doWork = [&ncOutputListList, &ncNcWrapperList, &options, this](String fileName, GribReadIndex readIndex) {

			auto gribOutput = ncNcWrapperList[fileName]->getData(readIndex, options);
			gribOutput.addDimension(readIndex._var->getName());
			gribOutput.ClipIf(options);
			float optionsFillValue = options.getWriter().getFillValue();
			if (optionsFillValue != 0.0f)
			{
				if (!gribOutput._fillValue.has_value()) {
					gribOutput._fillValue = optionsFillValue;
				}
			}
			return (VolumeGridData)gribOutput;
			};

		size_t comp = data.size();
		for (size_t i = 0; i < comp; i++)
		{
			std::vector<std::future<VolumeGridData> > fuVec;

			for (auto& ncOuputList : ncOutputListList)
			{
				auto& [fileName, data] = ncOuputList;
				const auto& readIndex = data[i];
				auto future = std::async(doWork, fileName, readIndex);
				fuVec.emplace_back(std::move(future));
			}

			AUTO_TIMER_ELAPSE_MESSAGE("GribCompute ");
			NcGridDataList dataListCompute;
			for (auto& x : fuVec)
			{
				try {
					dataListCompute.emplace_back(x.get());
				}
				catch (...) {
					OCPP_LOG_ERROR << "GribCompute::extract error.\n";
				}
			}
			auto ncGridData = _algorithm->onCompute(dataListCompute, options);
			options.getWriter().write(ncGridData, options);
		}


	}
}


